package cn.signalpha.modules.shop.listener;

import cn.signalpha.common.cache.ConfigCache;
import cn.signalpha.common.cache.ConfigKeys;
import cn.signalpha.common.dto.ConfigDTO;
import cn.signalpha.common.utils.Arith;
import cn.signalpha.common.utils.Assert;
import cn.signalpha.core.log.exception.ServiceException;
import cn.signalpha.core.tool.jackson.JsonUtil;
import cn.signalpha.core.tool.support.Kv;
import cn.signalpha.core.tool.utils.*;
import cn.signalpha.modules.com.entity.User;
import cn.signalpha.modules.com.service.UserService;
import cn.signalpha.modules.shop.dto.OrderConfirmDTO;
import cn.signalpha.modules.shop.dto.PublicityDTO;
import cn.signalpha.modules.shop.dto.PublicityGoodsDTO;
import cn.signalpha.modules.shop.entity.Publicity;
import cn.signalpha.modules.shop.entity.PublicityGoods;
import cn.signalpha.modules.shop.entity.UserAddress;
import cn.signalpha.modules.shop.entity.enums.CouponUseTypeEnum;
import cn.signalpha.modules.shop.entity.enums.LogisticsTypeEnum;
import cn.signalpha.modules.shop.entity.enums.PublicityTypeEnum;
import cn.signalpha.modules.shop.event.OrderConfirmEvent;
import cn.signalpha.modules.shop.order.OrderConfirmOrder;
import cn.signalpha.modules.shop.service.*;
import cn.signalpha.modules.shop.vo.OrderConfirmVO;
import cn.signalpha.modules.shop.vo.PublicityGoodsVO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 预生成订单
 */
@AllArgsConstructor
@Component("orderConfirmListener")
public class OrderConfirmListener {

	private final UserService userService;
	private final GoodsService goodsService;
	private final GoodsSkuService goodsSkuService;
	private final PublicityService publicityService;
	private final TransportService transportService;
	private final CouponUserService couponUserService;
	private final UserAddressService userAddressService;
	private final PublicityGoodsService publicityGoodsService;

    /**
     * 默认订单场景
     */
    @EventListener(OrderConfirmEvent.class)
    @Order(OrderConfirmOrder.DEFAULT)
    public void defaultConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();

        int goodsNumTotal = 0; double goodsPriceTotal = 0d; double orderPriceTotal = 0d;
        for (OrderConfirmVO.SellerCartItemVO shopCartItem : sellerCartVO.getSellerCartItemList()) {
            goodsNumTotal = shopCartItem.getGoodsNum() + goodsNumTotal;
            goodsPriceTotal = Arith.add(shopCartItem.getGoodsTotalPrice(), goodsPriceTotal);
			orderPriceTotal = Arith.add(shopCartItem.getGoodsTotalPrice(), orderPriceTotal);

			//初始化营销信息
			shopCartItem.setDeductPublicityId(0L);
			shopCartItem.setDeductPublicity(0d);
			shopCartItem.setDeductPublicityType(StringPool.EMPTY);
			shopCartItem.setDeductPublicityIsCoupon(1);
        }

		sellerCartVO.setTransportFee(0d);
		sellerCartVO.setDeductMoney(0d);
		sellerCartVO.setDeductIntegral(0d);
		sellerCartVO.setDeductIntegralMoney(0d);
		sellerCartVO.setDeductCouponSeller(0d);
		sellerCartVO.setDeductCouponSystem(0D);
		sellerCartVO.setDeductPublicity(0d);
		sellerCartVO.setDeductPublicityDetail(new ArrayList<>());
		sellerCartVO.setOrderPriceTotal(orderPriceTotal);
		sellerCartVO.setGoodsPriceTotal(goodsPriceTotal);
		sellerCartVO.setGoodsNumTotal(goodsNumTotal);
    }

	/**
	 * 运费场景
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.TRANSPORT)
	public void transportConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		OrderConfirmDTO orderConfirmDTO = event.getOrderConfirmDTO();
		List<OrderConfirmDTO.OrderShopDTO> orderShopList = orderConfirmDTO.getOrderShopList();

		double transportFee = 0d;
		int logisticsType = LogisticsTypeEnum.POST.getType();
		//如果开了同城配送，默认同城配送
		if(sellerCartVO.getSellerIsOpenDelivery() == 1){
			logisticsType = LogisticsTypeEnum.DELIVERY.getType();
		}

		Optional<OrderConfirmDTO.OrderShopDTO> optional = orderShopList.stream().filter(i -> i.getSellerId().equals(sellerCartVO.getSellerId())).findFirst();
		if(optional.isPresent()){
			if(Objects.equals(LogisticsTypeEnum.POST.getType(), optional.get().getLogisticsType())){
				logisticsType = LogisticsTypeEnum.POST.getType();
			}
			if(Objects.equals(LogisticsTypeEnum.PICK.getType(), optional.get().getLogisticsType())){
				logisticsType = LogisticsTypeEnum.PICK.getType();
			}
			if(Objects.equals(LogisticsTypeEnum.DELIVERY.getType(), optional.get().getLogisticsType())){
				logisticsType = LogisticsTypeEnum.DELIVERY.getType();
			}
		}

		//快递
		if(Objects.equals(LogisticsTypeEnum.POST.getType(), logisticsType)){
			UserAddress userAddress = userAddressService.getByUserId(orderConfirmDTO.getAddrId(), event.getUserId());
			for (OrderConfirmVO.SellerCartItemVO shopCartItem : sellerCartVO.getSellerCartItemList()) {
				// 用户地址如果为空，则表示该用户从未设置过任何地址相关信息
				if (userAddress != null) {
					transportFee = Arith.add(transportFee, transportService.calculateTransportFee(shopCartItem, userAddress));
				}
			}
		}
		//同城配送
		if(Objects.equals(LogisticsTypeEnum.DELIVERY.getType(), logisticsType)){
			if(ObjectUtil.isEmpty(sellerCartVO.getSellerDeliveryConfig())){
				throw new ServiceException("商家开启同城配送但并未设置具体配送信息，请联系商家处理");
			}
			transportFee = sellerCartVO.getSellerDeliveryConfig().getDeliveryPrice();
		}

		sellerCartVO.setTransportFee(transportFee);
		sellerCartVO.setLogisticsType(logisticsType);
		sellerCartVO.setOrderPriceTotal(Arith.add(sellerCartVO.getOrderPriceTotal(), transportFee));
	}

	/**
	 * 营销活动场景 限时秒杀
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.LIMIT_TIME_SEC_KILL)
	public void limitTimeSecKillConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		String type = PublicityTypeEnum.LIMIT_TIME_SEC_KILL.getType();

		double deductPublicity = 0d;
		for (OrderConfirmVO.SellerCartItemVO shopCartItem : sellerCartVO.getSellerCartItemList()) {
			//参与了其他优惠活动，直接跳过
			if(StringUtil.isNotBlank(shopCartItem.getDeductPublicityType())){
				continue;
			}
			PublicityGoodsVO publicityGoods = publicityGoodsService.getByGoodsIdAndType(sellerCartVO.getSellerId(), shopCartItem.getGoodsId(), type);
			if(ObjectUtil.isEmpty(publicityGoods)){
				continue;
			}
			PublicityGoodsDTO.LimitTimeSecKillDTO LimitTimeSecKillDTO = JsonUtil.parse(publicityGoods.getConfig(), PublicityGoodsDTO.LimitTimeSecKillDTO.class);
			if(ObjectUtil.isEmpty(LimitTimeSecKillDTO)){
				continue;
			}
			List<PublicityGoodsDTO.LimitTimeSecKillDetailDTO> detailList = LimitTimeSecKillDTO.getDetailList();
			Optional<PublicityGoodsDTO.LimitTimeSecKillDetailDTO> configOptional = detailList.stream().filter(item -> shopCartItem.getGoodsSpec().equals(item.getSpec())).findFirst();
			if(!configOptional.isPresent()){
				continue;
			}
			PublicityGoodsDTO.LimitTimeSecKillDetailDTO config = configOptional.get();
			if(ObjectUtil.isEmpty(config.getSalesVolume()) || ObjectUtil.isEmpty(config.getStock())){
				throw new ServiceException("该商品在营销活动中未设置库存或销量");
			}
			if(config.getSalesVolume() >= config.getStock()){
				continue;
			}

			//每人限买数
			int limitNum = LimitTimeSecKillDTO.getLimitNum() == 0 ? shopCartItem.getGoodsNum() : LimitTimeSecKillDTO.getLimitNum();
			//剩余可触发数
			int surplusNum = Math.min(config.getStock() - config.getSalesVolume(), limitNum);
			//实际可触发数
			int discountedNum = Math.min(surplusNum, shopCartItem.getGoodsNum());
			//非折扣商品数
			int regularNum =  Math.max(0, shopCartItem.getGoodsNum() - discountedNum);
			//非活动价 = 商品单价 * 非折扣商品数
			double regularPrice = Arith.mul(shopCartItem.getGoodsPrice(), regularNum);
			//活动价
			double discountRate = config.getPrice();
			//活动总价 = 折扣商品数 * 活动价
			double discountPrice = Arith.mul(discountedNum, discountRate);
			double orderPrice = Arith.add(discountPrice, regularPrice);

			double deductPrice = Arith.sub(shopCartItem.getGoodsTotalPrice(), orderPrice);
			shopCartItem.setOrderPrice(orderPrice);
			shopCartItem.setDeductPublicity(deductPrice);
			shopCartItem.setDeductPublicityId(publicityGoods.getPublicityId());
			shopCartItem.setDeductPublicityType(type);
			shopCartItem.setDeductPublicityGoodsNum(discountedNum);
			shopCartItem.setDeductPublicityIsCoupon(publicityGoods.getPublicityIsCoupon());
			shopCartItem.setDeductPublicityDetail(Kv.create().set("key", "限时秒杀").set("value", publicityGoods.getPublicityTitle()).set("endTime", publicityGoods.getEndTime()));

			deductPublicity = Arith.add(deductPublicity, deductPrice);
		}

		if(deductPublicity != 0){
			sellerCartVO.setOrderPriceTotal(Arith.sub(sellerCartVO.getOrderPriceTotal(), deductPublicity));
			sellerCartVO.setDeductPublicity(Arith.add(sellerCartVO.getDeductPublicity(), deductPublicity));
			sellerCartVO.getDeductPublicityDetail().add(Kv.create().set("key", "限时秒杀").set("value", deductPublicity));
		}
	}

	/**
	 * 营销活动场景 限时折扣
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.LIMIT_TIME_DISCOUNT)
	public void limitTimeDiscountConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		String type = PublicityTypeEnum.LIMIT_TIME_DISCOUNT.getType();

		double deductPublicity = 0d;
		for (OrderConfirmVO.SellerCartItemVO shopCartItem : sellerCartVO.getSellerCartItemList()) {
			//参与了其他优惠活动，直接跳过
			if(StringUtil.isNotBlank(shopCartItem.getDeductPublicityType())){
				continue;
			}
			PublicityGoodsVO publicityGoods = publicityGoodsService.getByGoodsIdAndType(sellerCartVO.getSellerId(), shopCartItem.getGoodsId(), type);
			if(ObjectUtil.isEmpty(publicityGoods)){
				continue;
			}
			PublicityGoodsDTO.LimitTimeDiscountDTO limitTimeDiscountDTO = JsonUtil.parse(publicityGoods.getConfig(), PublicityGoodsDTO.LimitTimeDiscountDTO.class);
			if(ObjectUtil.isEmpty(limitTimeDiscountDTO)){
				continue;
			}
			List<PublicityGoodsDTO.LimitTimeDiscountDetailDTO> detailList = limitTimeDiscountDTO.getDetailList();
			Optional<PublicityGoodsDTO.LimitTimeDiscountDetailDTO> configOptional = detailList.stream().filter(item -> shopCartItem.getGoodsSpec().equals(item.getSpec())).findFirst();
			if(!configOptional.isPresent()){
				continue;
			}
			PublicityGoodsDTO.LimitTimeDiscountDetailDTO config = configOptional.get();
			if(ObjectUtil.isEmpty(config.getSalesVolume()) || ObjectUtil.isEmpty(config.getStock())){
				throw new ServiceException("该商品在营销活动中未设置库存或销量");
			}
			if(config.getSalesVolume() >= config.getStock()){
				continue;
			}

			//每人限买数
			int limitNum = limitTimeDiscountDTO.getLimitNum() == 0 ? shopCartItem.getGoodsNum() : limitTimeDiscountDTO.getLimitNum();
			//剩余可触发数
			int surplusNum = Math.min(config.getStock() - config.getSalesVolume(), limitNum);
			//实际可触发数
			int discountedNum = Math.min(surplusNum, shopCartItem.getGoodsNum());
			//非折扣商品数
			int regularNum =  Math.max(0, shopCartItem.getGoodsNum() - discountedNum);
			//非活动价 = 商品单价 * 非折扣商品数
			double regularPrice = Arith.mul(shopCartItem.getGoodsPrice(), regularNum);

			double orderPrice = shopCartItem.getOrderPrice();
			if(limitTimeDiscountDTO.getType() == 1){
				//折扣率
				double discountRate = Arith.div(config.getPrice(), 10, 3);
				//活动总价 = 折扣商品数 * 商品单价 * 折扣率
				double discountPrice = Arith.round(Arith.mul(Arith.mul(discountedNum, shopCartItem.getGoodsPrice()), discountRate)).doubleValue();
				orderPrice = Arith.add(discountPrice, regularPrice);
			}else if(limitTimeDiscountDTO.getType() == 2){
				//立减价
				double discountRate = config.getPrice();
				//活动总价 = 折扣商品数 * (商品单价 - 立减价)
				double discountPrice = Arith.mul(discountedNum, Arith.sub(shopCartItem.getGoodsPrice(), discountRate));
				orderPrice = Arith.add(discountPrice, regularPrice);
			}else if(limitTimeDiscountDTO.getType() == 3){
				//活动价
				double discountRate = config.getPrice();
				//活动总价 = 折扣商品数 * 活动价
				double discountPrice = Arith.mul(discountedNum, discountRate);
				orderPrice = Arith.add(discountPrice, regularPrice);
			}

			//折扣了多少
			double deductPrice = Arith.sub(shopCartItem.getGoodsTotalPrice(), orderPrice);
			shopCartItem.setOrderPrice(orderPrice);
			shopCartItem.setDeductPublicity(deductPrice);
			shopCartItem.setDeductPublicityId(publicityGoods.getPublicityId());
			shopCartItem.setDeductPublicityType(type);
			shopCartItem.setDeductPublicityGoodsNum(discountedNum);
			shopCartItem.setDeductPublicityIsCoupon(publicityGoods.getPublicityIsCoupon());
			shopCartItem.setDeductPublicityDetail(Kv.create().set("key", "限时折扣").set("value", publicityGoods.getPublicityTitle()).set("endTime", publicityGoods.getEndTime()));
			deductPublicity = Arith.add(deductPublicity, deductPrice);
		}

		if(deductPublicity != 0){
			sellerCartVO.setOrderPriceTotal(Arith.sub(sellerCartVO.getOrderPriceTotal(), deductPublicity));
			sellerCartVO.setDeductPublicity(Arith.add(sellerCartVO.getDeductPublicity(), deductPublicity));
			sellerCartVO.getDeductPublicityDetail().add(Kv.create().set("key", "限时折扣").set("value", deductPublicity));
		}
	}


	/**
	 * 营销活动场景 满减活动
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.FULL_SUB_FULL_DISCOUNT)
	public void fullSubFullDiscountConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		String type = PublicityTypeEnum.FULL_SUB_FULL_DISCOUNT.getType();

		double deductPublicity = 0d;
		List<Publicity> publicityList = publicityService.listBySellerIdAndType(sellerCartVO.getSellerId(), type);
		for(Publicity publicity : publicityList){
			PublicityDTO.fullSubFullDiscountDTO config = JsonUtil.parse(publicity.getConfig(), PublicityDTO.fullSubFullDiscountDTO.class);
			if(ObjectUtil.isEmpty(config) || ObjectUtil.isEmpty(config.getPattern())){
				continue;
			}

			//参与该活动的商品
			double orderPriceTotal = 0d;
			List<OrderConfirmVO.SellerCartItemVO> joinShopCartItemList = new ArrayList<>();
			for (OrderConfirmVO.SellerCartItemVO shopCartItem : sellerCartVO.getSellerCartItemList()) {
				//参与了其他优惠活动，直接跳过
				if(StringUtil.isNotBlank(shopCartItem.getDeductPublicityType())){
					continue;
				}
				//商品是否有参与
				long count = publicityGoodsService.count(Wrappers.<PublicityGoods>lambdaQuery()
					.eq(PublicityGoods::getGoodsId, shopCartItem.getGoodsId())
					.eq(PublicityGoods::getPublicityId, publicity.getId())
				);
				if(count > 0){
					joinShopCartItemList.add(shopCartItem);
					orderPriceTotal = Arith.add(orderPriceTotal, shopCartItem.getOrderPrice());
				}
			}
			if(CollectionUtil.isEmpty(joinShopCartItemList)){
				continue;
			}

			//满减金额
			double reductionAmount = 0d;
			if(config.getPattern() == 1){
				for(PublicityDTO.fullSubFullDiscountDetailDTO detail : config.getDetailList()){
					if(orderPriceTotal >= detail.getFullHowMany()){
						reductionAmount = detail.getSubHowMany();
					}
				}
			}else if(config.getPattern() == 2){
				int times = (int) Arith.div(orderPriceTotal, config.getFullHowMany());
				reductionAmount = Math.min(Arith.mul(times, config.getSubHowMany()), config.getMaxHowMany());
			}
			if(reductionAmount <= 0){
				continue;
			}

			//总共满减金额
			double deductMoney = Math.min(orderPriceTotal, reductionAmount);
			//明细抵扣金额累计
			double itemDeductMoneyTotal = 0d;
			//计算抵扣的权重
			for(OrderConfirmVO.SellerCartItemVO shopCartItem : joinShopCartItemList){
				if(shopCartItem.getOrderPrice() <= 0){
					continue;
				}
				//最后一个元素需要直接做减法
				double itemDeductMoney, itemOrderPrice;
				double itemWight = Arith.div(shopCartItem.getOrderPrice(), orderPriceTotal, 5);
				if(joinShopCartItemList.size() - 1 == joinShopCartItemList.indexOf(shopCartItem)){
					itemDeductMoney = Arith.round(Arith.sub(deductMoney, itemDeductMoneyTotal)).doubleValue();
				}else {
					itemDeductMoney = Arith.round(Arith.mul(deductMoney, itemWight)).doubleValue();
				}
				itemOrderPrice = Arith.sub(shopCartItem.getOrderPrice(), itemDeductMoney);
				itemDeductMoneyTotal = Arith.add(itemDeductMoneyTotal, itemDeductMoney);
				shopCartItem.setOrderPrice(itemOrderPrice);
				shopCartItem.setDeductPublicity(itemDeductMoney);
				shopCartItem.setDeductPublicityId(publicity.getId());
				shopCartItem.setDeductPublicityType(type);
				shopCartItem.setDeductPublicityIsCoupon(publicity.getIsCoupon());
				shopCartItem.setDeductPublicityDetail(Kv.create().set("key", "满减活动").set("value", publicity.getTitle()).set("endTime", publicity.getEndTime()));
			}
			deductPublicity = reductionAmount;
		}

		if(deductPublicity != 0){
			sellerCartVO.setOrderPriceTotal(Arith.sub(sellerCartVO.getOrderPriceTotal(), deductPublicity));
			sellerCartVO.setDeductPublicity(Arith.add(sellerCartVO.getDeductPublicity(), deductPublicity));
			sellerCartVO.getDeductPublicityDetail().add(Kv.create().set("key", "满减活动").set("value", deductPublicity));
		}
	}

	/**
	 * 营销活动场景 N元N件
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.N_MONEY_N_PIECE)
	public void nMoneyNPieceConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		String type = PublicityTypeEnum.N_MONEY_N_PIECE.getType();

		double deductPublicity = 0d;
		List<Publicity> publicityList = publicityService.listBySellerIdAndType(sellerCartVO.getSellerId(), type);
		for(Publicity publicity : publicityList){
			PublicityDTO.NMoneyNPiecePDTO config = JsonUtil.parse(publicity.getConfig(), PublicityDTO.NMoneyNPiecePDTO.class);
			if(ObjectUtil.isEmpty(config) || ObjectUtil.isEmpty(config.getSpec()) || ObjectUtil.isEmpty(config.getMoney())){
				continue;
			}

			//N元
			int nSpec = config.getSpec();
			//N件
			double nMoney = config.getMoney();
			//参与N元N件列表
			List<OrderConfirmVO.SellerCartItemVO> joinShopCartItemList = new ArrayList<>();
			//不合符N元N件列表
			List<OrderConfirmVO.SellerCartItemVO> outShopCartItemList = new ArrayList<>();
			Iterator<OrderConfirmVO.SellerCartItemVO> it = sellerCartVO.getSellerCartItemList().iterator();
			while(it.hasNext()){
				OrderConfirmVO.SellerCartItemVO shopCartItem = it.next();
				//参与了其他优惠活动，直接跳过
				if(StringUtil.isNotBlank(shopCartItem.getDeductPublicityType())){
					continue;
				}
				//商品是否有参与
				long count = publicityGoodsService.count(Wrappers.<PublicityGoods>lambdaQuery()
					.eq(PublicityGoods::getGoodsId, shopCartItem.getGoodsId())
					.eq(PublicityGoods::getPublicityId, publicity.getId())
				);
				if(count == 0){
					continue;
				}
				shopCartItem.setDeductPublicityType(type);
				shopCartItem.setDeductPublicityId(publicity.getId());
				shopCartItem.setDeductPublicityIsCoupon(publicity.getIsCoupon());
				shopCartItem.setDeductPublicityDetail(Kv.create().set("key", "N元N件").set("value", publicity.getTitle()));

				//把商品拆成一件一件
				for(int i = 0; i < shopCartItem.getGoodsNum(); i++){
					OrderConfirmVO.SellerCartItemVO itemVO = Objects.requireNonNull(
						BeanUtil.copy(shopCartItem, OrderConfirmVO.SellerCartItemVO.class)
					);
					itemVO.setGoodsNum(1);
					itemVO.setGoodsTotalPrice(itemVO.getGoodsPrice());
					itemVO.setOrderPrice(itemVO.getGoodsPrice());
					joinShopCartItemList.add(itemVO);
				}
				it.remove();
			}

			//不触发N元N件
			if(joinShopCartItemList.size() < nSpec){
				joinShopCartItemList.stream().collect(Collectors.groupingBy(OrderConfirmVO.SellerCartItemVO::getGoodsId, LinkedHashMap::new, Collectors.toList())).forEach((goodsId, item) -> {
					OrderConfirmVO.SellerCartItemVO sellerCartItemVO = Objects.requireNonNull(BeanUtil.copy(item.get(0), OrderConfirmVO.SellerCartItemVO.class));
					sellerCartItemVO.setGoodsNum(item.size());
					sellerCartItemVO.setGoodsTotalPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getGoodsTotalPrice).sum()).doubleValue());
					sellerCartItemVO.setOrderPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getOrderPrice).sum()).doubleValue());
					sellerCartItemVO.setDeductPublicityDetail(Kv.create().setAll(sellerCartItemVO.getDeductPublicityDetail()).set("status", 0));
					sellerCartVO.getSellerCartItemList().add(sellerCartItemVO);
				});
				continue;
			}

			//过滤不合符的商品
			int outNum = joinShopCartItemList.size() % nSpec;
			for(int num = 0; num < outNum; num++){
				outShopCartItemList.add(joinShopCartItemList.remove(joinShopCartItemList.size() - 1));
			}

			//计算权重，并且根据n元n次的触发次数进行价格补正
			double itemWight = Arith.div(1, joinShopCartItemList.size(), 5);
			double itemWightMoney = Arith.mul(nMoney, Arith.div(joinShopCartItemList.size(), nSpec));
			double orderPriceTotal = 0, orderPriceOld = 0;
			for (OrderConfirmVO.SellerCartItemVO joinShopCartItem : joinShopCartItemList) {
				//每次循环到N的时候，就作为最后一个元素，需要做减法处理
				double itemOrderPrice;
				if((joinShopCartItemList.indexOf(joinShopCartItem) + 1) % nSpec == 0){
					//对触发次数进行价格补正
					double number = Arith.div(joinShopCartItemList.indexOf(joinShopCartItem) + 1, nSpec);
					double money = Arith.mul(nMoney, number);
					itemOrderPrice = Arith.round(Arith.sub(money, orderPriceTotal)).doubleValue();
				}else {
					itemOrderPrice = Arith.round(Arith.mul(itemWightMoney, itemWight)).doubleValue();
				}
				orderPriceOld = Arith.add(orderPriceOld, joinShopCartItem.getOrderPrice());
				orderPriceTotal = Arith.add(orderPriceTotal, itemOrderPrice);
				joinShopCartItem.setOrderPrice(itemOrderPrice);
			}

			//合并符合条件的相同商品
			joinShopCartItemList.stream().collect(Collectors.groupingBy(OrderConfirmVO.SellerCartItemVO::getGoodsId, LinkedHashMap::new, Collectors.toList())).forEach((goodsId, item) -> {
				//TODO 这里或许可以直接算出退款金额，方便后续退款
				OrderConfirmVO.SellerCartItemVO sellerCartItemVO = Objects.requireNonNull(BeanUtil.copy(item.get(0), OrderConfirmVO.SellerCartItemVO.class));
				sellerCartItemVO.setGoodsNum(item.size());
				sellerCartItemVO.setGoodsTotalPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getGoodsTotalPrice).sum()).doubleValue());
				sellerCartItemVO.setOrderPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getOrderPrice).sum()).doubleValue());
				sellerCartItemVO.setDeductPublicityDetail(Kv.create().setAll(sellerCartItemVO.getDeductPublicityDetail()).set("status", 1));
				sellerCartVO.getSellerCartItemList().add(sellerCartItemVO);
			});

			//合并不符合条件的相同商品
			outShopCartItemList.stream().collect(Collectors.groupingBy(OrderConfirmVO.SellerCartItemVO::getGoodsId, LinkedHashMap::new, Collectors.toList())).forEach((goodsId, item) -> {
				OrderConfirmVO.SellerCartItemVO sellerCartItemVO = Objects.requireNonNull(BeanUtil.copy(item.get(0), OrderConfirmVO.SellerCartItemVO.class));
				sellerCartItemVO.setGoodsNum(item.size());
				sellerCartItemVO.setOrderPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getOrderPrice).sum()).doubleValue());
				sellerCartItemVO.setGoodsTotalPrice(Arith.round(item.stream().mapToDouble(OrderConfirmVO.SellerCartItemVO::getGoodsTotalPrice).sum()).doubleValue());
				sellerCartItemVO.setDeductPublicityDetail(Kv.create().setAll(sellerCartItemVO.getDeductPublicityDetail()).set("status", 0));
				sellerCartVO.getSellerCartItemList().add(sellerCartItemVO);
			});

			//计算最终的优惠价格
			if(orderPriceTotal > 0){
				double deductPrice = Arith.sub(orderPriceOld, orderPriceTotal);
				deductPublicity = Arith.add(deductPublicity, deductPrice);
			}
		}

		if(deductPublicity != 0){
			sellerCartVO.setOrderPriceTotal(Arith.sub(sellerCartVO.getOrderPriceTotal(), deductPublicity));
			sellerCartVO.setDeductPublicity(Arith.add(sellerCartVO.getDeductPublicity(), deductPublicity));
			sellerCartVO.getDeductPublicityDetail().add(Kv.create().set("key", "N元N件").set("value", deductPublicity));
		}
	}

	/**
	 * 余额抵扣场景
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.MONEY_DEDUCT)
	public void moneyDeductConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		OrderConfirmDTO orderConfirmDTO = event.getOrderConfirmDTO();
		if(ObjectUtil.isEmpty(orderConfirmDTO.getDeductMoney()) || orderConfirmDTO.getDeductMoney() <= 0){
			return;
		}

		User user = userService.getById(event.getUserId());
		Assert.isTrue(user.getMoney() >= orderConfirmDTO.getDeductMoney(), StringUtil.format("余额抵扣最多为{}", user.getMoney()));

		//订单金额
		double orderPriceTotal = sellerCartVO.getOrderPriceTotal();
		//抵扣金额
		double deductMoney = Math.min(orderPriceTotal, orderConfirmDTO.getDeductMoney());
		//明细抵扣金额累计
		double itemDeductMoneyTotal = 0d;
		//计算抵扣的权重
		for(OrderConfirmVO.SellerCartItemVO sellerCartItemVO : sellerCartVO.getSellerCartItemList()){
			if(sellerCartItemVO.getOrderPrice() <= 0){
				continue;
			}
			//最后一个元素需要直接做减法
			double itemDeductMoney, itemOrderPrice;
			double itemWight = Arith.div(sellerCartItemVO.getOrderPrice(), orderPriceTotal, 5);
			if(sellerCartVO.getSellerCartItemList().size() - 1 == sellerCartVO.getSellerCartItemList().indexOf(sellerCartItemVO)){
				itemDeductMoney = Arith.round(Arith.sub(deductMoney, itemDeductMoneyTotal)).doubleValue();
			}else {
				itemDeductMoney = Arith.round(Arith.mul(deductMoney, itemWight)).doubleValue();
			}
			itemOrderPrice = Arith.sub(sellerCartItemVO.getOrderPrice(), itemDeductMoney);
			itemDeductMoneyTotal = Arith.add(itemDeductMoneyTotal, itemDeductMoney);
			sellerCartItemVO.setOrderPrice(itemOrderPrice);
			sellerCartItemVO.setDeductMoney(itemDeductMoney);
		}
		//更新抵扣金额和订单实际支付金额
		sellerCartVO.setDeductMoney(deductMoney);
		sellerCartVO.setOrderPriceTotal(Arith.sub(orderPriceTotal, deductMoney));
		//更新剩余的抵扣金额
		orderConfirmDTO.setDeductMoney(Arith.sub(orderConfirmDTO.getDeductMoney(), deductMoney));
	}

	/**
	 * 积分抵扣场景
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.INTEGRAL_DEDUCT)
	public void integralDeductConfirmOrderEvent(OrderConfirmEvent event) {
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		OrderConfirmDTO orderConfirmDTO = event.getOrderConfirmDTO();
		if(ObjectUtil.isEmpty(orderConfirmDTO.getDeductIntegral()) || orderConfirmDTO.getDeductIntegral() <= 0){
			return;
		}

		//获取用户积分
		User user = userService.getById(event.getUserId());
		Assert.isTrue(user.getIntegral() >= orderConfirmDTO.getDeductIntegral(), StringUtil.format("积分抵扣最多为{}", user.getIntegral()));

		//积分规则转换
		ConfigDTO.ShopDTO config = ConfigCache.getObject(ConfigKeys.SHOP, ConfigDTO.ShopDTO.class);
		if(config.getIsOpenIntegral() == 0){
			throw new ServiceException("积分抵扣暂未开放");
		}
		//订单金额
		double orderPriceTotal = sellerCartVO.getOrderPriceTotal();
		//积分的实际金额
		double deductIntegralMoneyTotal = Arith.mul(Arith.div(orderConfirmDTO.getDeductIntegral(), config.getIntegralUnit()), config.getIntegralMoney());
		//根据订单实际要抵扣的金额
		double deductIntegralMoneyTotalActual = Math.min(orderPriceTotal, deductIntegralMoneyTotal);
		//重新转换为积分，得出用了多少积分，直接向上取整
		double deductIntegralTotal = Arith.mul(deductIntegralMoneyTotalActual, Arith.div(config.getIntegralUnit(), config.getIntegralMoney()));
		//明细抵扣金额累计
		double deductIntegralItemTotal = 0d;
		//计算抵扣的权重
		for(OrderConfirmVO.SellerCartItemVO sellerCartItemVO : sellerCartVO.getSellerCartItemList()){
			if(sellerCartItemVO.getOrderPrice() <= 0){
				continue;
			}
			//最后一个元素需要直接做减法
			double deductIntegralItem, orderPriceItem;
			double itemWight = Arith.div(sellerCartItemVO.getOrderPrice(), orderPriceTotal, 5);
			if(sellerCartVO.getSellerCartItemList().size() - 1 == sellerCartVO.getSellerCartItemList().indexOf(sellerCartItemVO)){
				deductIntegralItem = Arith.round(Arith.sub(deductIntegralMoneyTotalActual, deductIntegralItemTotal)).doubleValue();
			}else {
				deductIntegralItem = Arith.round(Arith.mul(deductIntegralMoneyTotalActual, itemWight)).doubleValue();
			}
			orderPriceItem = Arith.sub(sellerCartItemVO.getOrderPrice(), deductIntegralItem);
			sellerCartItemVO.setOrderPrice(orderPriceItem < 0 ? 0 : orderPriceItem);
			sellerCartItemVO.setDeductIntegral(Arith.mul(deductIntegralItem, config.getIntegralUnit()));
			sellerCartItemVO.setDeductIntegralMoney(deductIntegralItem);
			deductIntegralItemTotal = Arith.add(deductIntegralItemTotal, deductIntegralItem);
		}
		//更新抵扣金额和订单实际支付金额
		sellerCartVO.setDeductIntegral(deductIntegralTotal);
		sellerCartVO.setDeductIntegralMoney(deductIntegralItemTotal);
		sellerCartVO.setOrderPriceTotal(Arith.sub(orderPriceTotal, deductIntegralMoneyTotalActual));
		//更新剩余的抵扣金额
		orderConfirmDTO.setDeductIntegral(Arith.sub(orderConfirmDTO.getDeductIntegral(), deductIntegralTotal));
	}

	/**
	 * 优惠券场景
	 */
	@EventListener(OrderConfirmEvent.class)
	@Order(OrderConfirmOrder.COUPON)
	public void couponConfirmOrderEvent(OrderConfirmEvent event) {
		Long userId = event.getUserId();
		OrderConfirmDTO orderConfirmDTO = event.getOrderConfirmDTO();
		OrderConfirmVO.SellerCartVO sellerCartVO = event.getSellerCartVO();
		List<OrderConfirmDTO.OrderShopDTO> orderShopList = orderConfirmDTO.getOrderShopList();
		OrderConfirmDTO.OrderShopDTO orderShopDTO = orderShopList.stream().filter(i -> i.getSellerId().equals(sellerCartVO.getSellerId())).findFirst().orElse(null);
		List<OrderConfirmVO.SellerCartItemVO> sellerCartItemList = sellerCartVO.getSellerCartItemList();

		List<OrderConfirmVO.CouponVO> couponList = new ArrayList<>();
		List<OrderConfirmVO.CouponVO> couponNotList = new ArrayList<>();
		couponUserService.listByUserIdAndSellerId(userId, sellerCartVO.getSellerId()).forEach(couponUser -> {
			OrderConfirmVO.CouponVO couponVO = Objects.requireNonNull(BeanUtil.copy(couponUser, OrderConfirmVO.CouponVO.class));
			couponVO.setIsSelect(0);
			//商品券
			if(couponUser.getUseType().equals(CouponUseTypeEnum.GOODS.getType()) && StringUtil.isNoneBlank(couponUser.getPrimaryKey())){
				//交集
				List<Long> goodsIds = sellerCartItemList.stream().map(OrderConfirmVO.SellerCartItemVO::getGoodsId).collect(Collectors.toList());
				List<Long> intersection = Func.toLongList(couponUser.getPrimaryKey()).stream().filter(goodsIds::contains).collect(Collectors.toList());
				if(intersection.size() > 0){
					//如果交集中的商品有不支持优惠券的
					List<Long> removeGoodsIds = new ArrayList<>();
					intersection.forEach(goodsId -> {
						if(sellerCartItemList.stream().filter(i -> i.getGoodsId().equals(goodsId)).findFirst().get().getDeductPublicityIsCoupon() == 0){
							removeGoodsIds.add(goodsId);
						}
					});
					intersection.removeAll(removeGoodsIds);
					if(intersection.size() == 0){
						couponVO.setRemark("结算商品参与的活动不可与优惠券共享");
						couponNotList.add(couponVO);
					}else{
						//交集中的金额是否大于门槛
						double orderTotalPrice = Arith.round(sellerCartItemList.stream().filter(i -> intersection.contains(i.getGoodsId()))
							.mapToDouble(OrderConfirmVO.SellerCartItemVO::getOrderPrice).sum()).doubleValue();
						if(orderTotalPrice >= couponUser.getMinPrice()){
							couponVO.setTargetKey(Func.join(intersection));
							couponList.add(couponVO);
						}else{
							couponVO.setRemark("指定商品未达到最低消费金额");
							couponNotList.add(couponVO);
						}
					}
				}else{
					couponVO.setRemark("结算商品中无指定商品");
					couponNotList.add(couponVO);
				}
			}

			//商户券
			if(couponUser.getUseType().equals(CouponUseTypeEnum.SELLER.getType())){
				List<Long> goodsIds = sellerCartItemList.stream().map(OrderConfirmVO.SellerCartItemVO::getGoodsId).collect(Collectors.toList());
				//如果商品中有不支持优惠券的
				List<Long> removeGoodsIds = new ArrayList<>();
				goodsIds.forEach(goodsId -> {
					if(sellerCartItemList.stream().filter(i -> i.getGoodsId().equals(goodsId)).findFirst().get().getDeductPublicityIsCoupon() == 0){
						removeGoodsIds.add(goodsId);
					}
				});
				goodsIds.removeAll(removeGoodsIds);
				if(goodsIds.size() == 0){
					couponVO.setRemark("结算商品参与的活动不可与优惠券共享");
					couponNotList.add(couponVO);
				}else{
					//交集中的金额是否大于门槛
					double orderTotalPrice = Arith.round(sellerCartItemList.stream().filter(i -> goodsIds.contains(i.getGoodsId()))
						.mapToDouble(OrderConfirmVO.SellerCartItemVO::getOrderPrice).sum()).doubleValue();
					if(orderTotalPrice >= couponUser.getMinPrice()){
						couponVO.setTargetKey(Func.join(goodsIds));
						couponList.add(couponVO);
					}else{
						couponVO.setRemark("店铺商品未达到最消费金额");
						couponNotList.add(couponVO);
					}
				}
			}
		});

		sellerCartVO.setCouponsList(couponList.stream().sorted((u1, u2) -> u2.getMoney().compareTo(u1.getMoney())).collect(Collectors.toList()));
		sellerCartVO.setCouponNotList(couponNotList.stream().sorted((u1, u2) -> u2.getMoney().compareTo(u1.getMoney())).collect(Collectors.toList()));
		if(CollectionUtil.isEmpty(sellerCartVO.getCouponsList())){
			return;
		}

		//抵扣优惠券，0不使用，null默认一张
		OrderConfirmVO.CouponVO selectCouponVO = null;
		if(orderShopDTO != null){
			if(orderShopDTO.getCouponId() > 0){
				for (OrderConfirmVO.CouponVO couponVO : sellerCartVO.getCouponsList()) {
					if(couponVO.getId().equals(orderShopDTO.getCouponId())){
						couponVO.setIsSelect(1);
						selectCouponVO = couponVO;
					}
				}
			}
		}else {
			//自动选择金额最高的一张
			sellerCartVO.getCouponsList().get(0).setIsSelect(1);
			selectCouponVO = sellerCartVO.getCouponsList().get(0);
		}
		if(ObjectUtil.isEmpty(selectCouponVO)){
			return;
		}

		//该优惠券可使用的商品
		List<Long> goodsIds = Func.toLongList(selectCouponVO.getTargetKey());
		//牵扯到的商品和金额
		List<OrderConfirmVO.SellerCartItemVO> sellerCartItemNewList = new ArrayList<>();
		AtomicReference<Double> orderPriceTotal = new AtomicReference<>(0d);
		sellerCartVO.getSellerCartItemList().forEach(sellerCartItemVO -> {
			if(goodsIds.contains(sellerCartItemVO.getGoodsId()) && sellerCartItemVO.getOrderPrice() > 0){
				sellerCartItemNewList.add(sellerCartItemVO);
				orderPriceTotal.set(Arith.add(orderPriceTotal.get(), sellerCartItemVO.getOrderPrice()));
			}
		});

		//优惠券金额
		double deductCoupon = selectCouponVO.getMoney();
		//实际可以抵扣
		double deductCouponMoney = Math.min(orderPriceTotal.get(), deductCoupon);
		//明细抵扣金额累计
		double itemDeductCouponMoneyTotal = 0d;
		//计算抵扣的权重
		for(OrderConfirmVO.SellerCartItemVO sellerCartItemVO : sellerCartItemNewList){
			//最后一个元素需要直接做减法
			double itemDeductCouponMoney, itemOrderPrice;
			double itemWight = Arith.div(sellerCartItemVO.getOrderPrice(), orderPriceTotal.get(), 5);
			if(sellerCartItemNewList.size() - 1 == sellerCartItemNewList.indexOf(sellerCartItemVO)){
				itemDeductCouponMoney = Arith.round(Arith.sub(deductCouponMoney, itemDeductCouponMoneyTotal)).doubleValue();
			}else {
				itemDeductCouponMoney = Arith.round(Arith.mul(deductCouponMoney, itemWight)).doubleValue();
			}
			itemOrderPrice = Arith.sub(sellerCartItemVO.getOrderPrice(), itemDeductCouponMoney);
			itemDeductCouponMoneyTotal = Arith.add(itemDeductCouponMoneyTotal, itemDeductCouponMoney);
			sellerCartItemVO.setOrderPrice(itemOrderPrice);
			sellerCartItemVO.setDeductCouponSeller(itemDeductCouponMoney);
		}

		//更新抵扣金额和订单实际支付金额
		sellerCartVO.setDeductCouponSeller(deductCouponMoney);
		sellerCartVO.setOrderPriceTotal(Arith.sub(sellerCartVO.getOrderPriceTotal(), deductCouponMoney));
	}

}
